package com.shape.sdk;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.shape.sdk.base.IOUtils;
import com.shape.sdk.collect.FakeAntCollector;
import com.shape.sdk.collect.FizzoAntCollector;
import com.shape.sdk.collect.ICollector;
import com.shape.sdk.collect.UsbAntCollector;
import com.shape.sdk.net.CourseSyncResponse;
import com.shape.sdk.net.ShapeContants;
import com.shape.sdk.net.ShapeHttpClient;
import com.shape.sdk.protocol.Notification;
import com.shape.sdk.protocol.Schedule;
import com.squareup.wire.Wire;
import com.wandoujia.gson.Gson;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.fizzo.hub.sdk.utils.SerialU;

/**
 * Created by ouzhiyin on 17/01/2018.
 */

public class ShapeCenter {
  public enum PublicNotifyType {
    START,
    STOP,
    PAUSE,
    RESUME
  }
  private int storeId;
  private int stationId;
  private int stateionCount;
  private int collectType = 0;
  private Reporter reporter;
  private Context context;
  private List<Course> weekCourse;
  private Fitness currentFitness;
  private ICollector collector;
  private Handler handler;
  private boolean stop = false;
  private boolean syncCourse = false;
  private PushConnection pushConnection;
  private Listener listener;
  private PushConnection.Listener pushListener = new PushConnection.Listener() {
    @Override
    public void onNotification(Notification notification) {
      // TODO
      switch (notification.type) {
        case ShapeContants.NOTIFICATION_TYPE_SCHEDULE:
          break;
        case ShapeContants.NOTIFICATION_TYPE_BOOKING:
          break;
        case ShapeContants.NOTIFICATION_TYPE_BINDING:
          break;
        case ShapeContants.NOTIFICATION_TYPE_CHECKIN:
          if (currentFitness != null) {
            currentFitness.updateUsers();
          }
          Log.d("shapeInner", "receive NOTIFICATION_TYPE_CHECKIN");
          break;
        case ShapeContants.NOTIFICATION_TYPE_BEGIN:
          if (listener != null && currentFitness != null
              && currentFitness.getState() == Fitness.State.READY) {
            Wire wire = new Wire();
            Schedule schedule = null;
            try {
              schedule = wire.parseFrom(notification.data.toByteArray(),
                  Schedule.class);
            } catch (IOException e) {
              e.printStackTrace();
            }
            if (schedule != null) {
              Log.d("shapeInner", "receive NOTIFICATION_TYPE_BEGIN scheduleId="
                  + schedule.scheduleId
                  + " showTime" + schedule.showTime);
              if (schedule.scheduleId == currentFitness.getCourse().scheduleId) {
                long showTime = schedule.showTime;
                showTime = showTime * 1000;
                listener.onEvent(PublicNotifyType.START, showTime);
              }
            }
          }
          break;
        case ShapeContants.NOTIFICATION_TYPE_FINISH:
          if (listener != null && currentFitness != null
              && currentFitness.getState() == Fitness.State.RUNNING) {
            Wire wire = new Wire();
            Schedule schedule = null;
            try {
              schedule = wire.parseFrom(notification.data.toByteArray(),
                  Schedule.class);
            } catch (IOException e) {
              e.printStackTrace();
            }
            if (schedule != null) {
              Log.d("shapeInner", "receive NOTIFICATION_TYPE_FINISH scheduleId="
                  + schedule.scheduleId
                  + " showTime" + schedule.showTime);
              if (schedule.scheduleId == currentFitness.getCourse().scheduleId) {
                long showTime = schedule.showTime;
                showTime = showTime * 1000;
                listener.onEvent(PublicNotifyType.STOP, showTime);
              }
            }
          }
          break;
        case ShapeContants.NOTIFICATION_TYPE_EMERGENCY:
          break;
        case ShapeContants.NOTIFICATION_TYPE_UPGRADE:
          break;
        default:
          break;
      }
//      listener.onEvent(PublicNotifyType.START.ordinal(), System.currentTimeMillis() + 3000);
    }
  };

  public interface Listener {
    void onEvent(PublicNotifyType type, long doTimestamp);
  }

  public ShapeCenter(Context context) {
    this.context = context;
    collector = new UsbAntCollector(context);
  }

  public void init(Listener listener) {
    // TODO load param from sdcard file
    File file = new File("/sdcard/shapefitness/init.json");
    if (file.exists() && file.canRead()) {
      try {
        String json = IOUtils.readString(file);
        Gson gson = new Gson();
        InitConfig config = gson.fromJson(json, InitConfig.class);
        this.storeId = config.storeId;
        this.stationId = config.stationId;
        this.stateionCount = config.stationCount;
        this.collectType= config.collectType;
        doInit(listener);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  public void init(int storeId, int stationId, int stationCount, Listener listener) {
    this.storeId = storeId;
    this.stationId = stationId;
    this.stateionCount = stationCount;
    doInit(listener);
  }

  private void doInit(Listener listener) {
    weekCourse = FakeDataManager.getWeekCourse();
    // TODO replace fake
    switch (collectType) {
      case 0:
        Log.d("shapeInner", "init FakeAntCollector");
        collector = new FakeAntCollector();
        break;
      case 1:
        Log.d("shapeInner", "init FizzoAntCollector");
        collector = new FizzoAntCollector(context);
        break;
      case 2:
        Log.d("shapeInner", "init UsbAntCollector");
        collector = new UsbAntCollector(context);
        break;
    }
    this.listener = listener;
//    collector = new FizzoAntCollector(context);
    handler = new Handler(Looper.getMainLooper());
    pushConnection = new PushConnection(storeId, stationId, SerialU.getCpuSerial());
    pushConnection.start(pushListener);
    reporter = new Reporter(context);
    queryCourseUpdateAsync();
  }

  public Course getNextCourse() {
    int currentScheduleId = 0;
//    if (currentFitness != null) {
//      currentScheduleId = currentFitness.getCourse().getScheduleId();
//    }

    Course result = getNextCourse(currentScheduleId);
    if (result == null && !syncCourse) {
      queryCourseUpdateAsync();
    }
    return result;
  }

  public Course getNextCourse(int currentScheduleId) {
    if (weekCourse == null) {
      return null;
    }
    long currentTime = System.currentTimeMillis();
    for (Course course : weekCourse) {
      if (currentScheduleId > 0) {
        if (course.getScheduleId() > currentScheduleId) {
          return course;
        }
      } else if (course.startTime + 15 * 60 * 1000 > currentTime) {
        return course;
      }
    }
    return null;
  }

  public Fitness loadCourse(Course course) {
    currentFitness = new Fitness(context, stationId, stateionCount, reporter, course, collector);
    return currentFitness;
  }


  public void close() {
    stop = true;
    if (currentFitness != null) {
      currentFitness.stop();
      currentFitness = null;
    }
    if (collector != null) {
      collector.stop();
    }
  }
//
//  private void queryCourseUpdateFake() {
//    handler.postDelayed(new Runnable() {
//      @Override
//      public void run() {
//        if (!stop) {
//          weekCourse = FakeDataManager.getWeekCourse();
////          queryCourseUpdateAsync();
//        }
//      }
//    }, 10000);
//  }

  private void queryCourseUpdateAsync() {
    syncCourse = true;
    final Map<String, String> map = new HashMap<>();
    map.put("store_id", String.valueOf(storeId));
    map.put("station_id", String.valueOf(stationId));
    ShapeHttpClient<CourseSyncResponse> client = new ShapeHttpClient<>(CourseSyncResponse.class);
    client.requestGetAsync(ShapeContants.QUERY_COURSE_SYNC, map, new ShapeHttpClient.Listener<CourseSyncResponse>() {
      @Override
      public void onSuccess(CourseSyncResponse response) {
        // TODO ouzhiyin
        weekCourse = FakeDataManager.getWeekCourse();
        if (weekCourse == null) {
          weekCourse = response.getCourseList();
        }
        syncCourse = false;
      }

      @Override
      public void onError(int errorCode, String msg) {
        syncCourse = false;
      }
    });
  }

//    public void fakeEventNotify(final PublicNotifyType notifyType) {
//      handler.postDelayed(new Runnable() {
//        @Override
//        public void run() {
//          if (listener != null) {
//            listener.onEvent(notifyType, System.currentTimeMillis() + 3000);
//          }
//        }
//      }, 2000);
//    }
}
